package org.bee.tl.core.io;

import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

public class ByteWriter extends Writer {
	protected Writer charWriter = null;
	protected OutputStreamByteWriter byteWriter = null;
	protected String charset = null;
	protected boolean isCharWriter = false;
	protected boolean isByteStream = false;
	protected boolean isTemp = false;

	ByteWriter() {

	}

	ByteWriter(ByteWriter w) {
		this.charset = w.charset;
		this.byteWriter = w.byteWriter;
		this.charWriter = w.charWriter;
		this.isCharWriter = w.isCharWriter;
		this.isByteStream = w.isByteStream;
		this.isTemp = w.isTemp;
	}

	public ByteWriter(Writer w) {
		this.charWriter = w;
		isCharWriter = true;
	}

	protected ByteWriter(Writer w, boolean isTemp) {
		this(w);
		this.isTemp = isTemp;
	}

	public ByteWriter(OutputStream w, String charset)
			throws UnsupportedEncodingException {
		this.charset = charset;
		this.byteWriter = new OutputStreamByteWriter(w, charset);
		isCharWriter = false;
	}

	protected ByteWriter(OutputStream w, String charset, boolean isTemp)
			throws UnsupportedEncodingException {
		this(w, charset);
		this.isTemp = isTemp;
	}

	@Override
	public void write(char[] cbuf, int off, int len) throws IOException {
		if (isCharWriter) {
			charWriter.write(cbuf, off, len);
		} else {
			byteWriter.write(cbuf, off, len);
		}

	}

	public void write(byte[] bs) throws IOException {
		if (isCharWriter) {

			throw new IllegalArgumentException("Can not write byte[]");
		} else {
			byteWriter.write(bs);
		}
	}

	public ByteWriter getTempWriter() {
		if (isCharWriter) {
			return new ByteWriter(new CharArrayWriter(), true);
		} else {
			try {
				return new ByteWriter(new ByteArrayOutputStream(), charset,
						true);
			} catch (UnsupportedEncodingException e) {
				// could not happen,ignore
				throw new RuntimeException(e.getMessage());
			}
		}
	}

	public String toString() {

		if (isCharWriter) {
			try {
				charWriter.flush();
			} catch (IOException e) {
				;
			}
			return this.charWriter.toString();
		} else if (this.isTemp) {

			try {
				return new String(this.getTempByte(), charset);
			} catch (UnsupportedEncodingException e) {
				// could not happen,ignore
				throw new RuntimeException(e.getMessage());
			}
		} else {
			return super.toString();
		}
	}

	public String getTempString() {
		if (isCharWriter && isTemp) {
			try {
				this.flush();
			} catch (IOException e) {
				// never happen
				e.printStackTrace();
			}
			return this.charWriter.toString();
		} else {
			throw new IllegalArgumentException(
					"Can not get String for this writer");
		}
	}

	public byte[] getTempByte() {
		try {
			this.flush();
		} catch (IOException e) {
			// never happen;
		}
		if (!isCharWriter && isTemp) {
			return ((ByteArrayOutputStream) this.byteWriter.getOutputStream())
					.toByteArray();
		} else {
			throw new IllegalArgumentException(
					"Can not get String for this writer");
		}
	}

	@Override
	public void flush() throws IOException {
		if (isCharWriter) {
			charWriter.flush();
		} else {
			byteWriter.flush();
		}

	}

	@Override
	public void close() throws IOException {
		if (isCharWriter) {
			charWriter.close();
		} else {
			byteWriter.close();
		}

	}

	public static void main(String[] args) {
		// ByteWriter writer = new ByteWriter(new StringWriter());
		// Object b = new byte[5];
		// writer.write(b);
	}

}
